GitHub CI 配置编写指南
GitHub Actions 是 GitHub 提供的持续集成和持续部署 (CI/CD) 服务,通过编写工作流配置文件 (.github/workflows/*.yml) 来自动化软件开发流程。本指南将详细介绍如何编写 GitHub Actions 的工作流配置文件。
基本概念
GitHub Actions 工作流是一个可 配置的自动化过程,由 YAML 格式的配置文件定义。这些文件必须保存在仓库的 .github/workflows 目录中,扩展名为 .yml 或 .yaml。一个仓库可以包含多个工作流文件,每个文件定义不同的自动化流程。3 4
工作流可以在仓库中的事件触发时运行,也可以手动触发或按照预定的时间表运行。每个工作流由一个或多个作业组成,作业可以并行或顺序执行。4
工作流文件结构
一个典型的 GitHub Actions 工作流文件结构如下:
name: CI Workflow
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '16'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
这个简单的工作流在推送到 main 分支或创建针对 main 分支的 pull request 时触发,在 Ubuntu 最新版本上运行一系列步骤,包括检出代码、设置 Node.js 环境、安装依赖和运行测试。1 2
工作流组件详解
1. name(工作流名称)
可选字段,用于在 GitHub 仓库的 Actions 页面上显示工作流的名称:
name: Build and Test
如果省略此字段,GitHub 将使用工作流文件的相对路径作为名称。1
2. on(触发器)
指定触发工作流的事件:
# 简单配置
on: push
# 多个事件触发
on: [push, pull_request]
# 详细配置
on:
# 推送到特定分支时触发
push:
branches: [ main, develop ]
paths-ignore: [ 'docs/**', '**.md' ]
# 创建 PR 时触发
pull_request:
branches: [ main ]
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
# 定时触发
schedule:
- cron: '0 0 * * *' # 每天午夜运行
GitHub Actions 支持多种触发事件类型,包括代码推送、pull request、定时任务、手动触发等。1 4
3. jobs(作业)
工作流由一个或多个作业组成,默认情况下作业并行运行:
jobs:
build:
name: Build Application
runs-on: ubuntu-latest
steps:
# 构建步骤...
test:
name: Run Tests
runs-on: windows-latest
steps:
# 测试步骤...
每个作业必须有一个 ID(如上例中的 build 和 test),并且可以包含以下属性:
name:作业的显示名称runs-on:运行作业的环境(如 ubuntu-latest, windows-latest, macos-latest)needs:指定依赖的其他作业,用于创建顺序执行的作业if:条件表达式,决定是否执行此作业steps:定义作业中的步骤序列strategy:定义构建矩阵,用于在多种配置下运行作业environment:指定部署环境
4. steps(步骤)
步骤是作业中执行的任务序列,可以运行命令、设置环境、使用 Actions 等:
steps:
# 检出代码
- name: Checkout code
uses: actions/checkout@v3
# 设置 Java 环境
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
# 运行命令
- name: Build with Maven
run: mvn -B package --file pom.xml
# 使用环境变量
- name: Deploy to staging
run: ./deploy.sh
env:
SERVER_URL: ${{ secrets.STAGING_URL }}
API_TOKEN: ${{ secrets.API_TOKEN }}
每个步骤可以包含以下主要属性:
name:步骤的显示名称uses:指定要使用的 Actionrun:运行的命令行命令with:Action 的输入参数env:设置步骤的环境变量if:条件表达式,决定是否执行此步骤continue-on-error:指定步骤失败时是否继续执行后续步骤
5. strategy(策略)
使用策略可以创建构建矩阵,在多种配置下运行同一作业:
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [14.x, 16.x, 18.x]
include:
- os: ubuntu-latest
node-version: 18.x
npm-cache: true
exclude:
- os: windows-latest
node-version: 14.x
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
上面的配置会创建一个 3×3 的矩阵,在三种操作 系统上分别测试三个 Node.js 版本,同时添加了一个特殊配置并排除了一个组合。1
6. 环境与密钥
GitHub Actions 可以使用仓库中设置的密钥和变量:
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v3
- name: Deploy to production
run: ./deploy.sh
env:
API_TOKEN: ${{ secrets.API_TOKEN }}
CONFIG_FILE: ${{ vars.CONFIG_FILE }}
使用 secrets 上下文访问密钥,使用 vars 上下文访问变量。通过指定 environment,可以使用特定环境的密钥和变量。1 4
高级特性
1. 作业依赖和条件执行
使用 needs 和 if 可以创建复杂的工作流:
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "Building..."
test:
needs: build
runs-on: ubuntu-latest
steps:
- run: echo "Testing..."
deploy:
needs: [build, test]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- run: echo "Deploying..."
上例中,test 作业会在 build 作业成功后运行,而 deploy 作业需要 build 和 test 都成功,并且只在推送到 main 分支时执行。1 3
2. 复用工作流
可以使用 workflow_call 事件创建可复用的工作流:
# 可复用工作流:.github/workflows/reusable.yml
name: Reusable Workflow
on:
workflow_call:
inputs:
environment:
required: true
type: string
secrets:
api-token:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
steps:
- uses: actions/checkout@v3
- name: Deploy
run: ./deploy.sh
env:
API_TOKEN: ${{ secrets.api-token }}
然后在其他工作流中调用:
# 调用工作流:.github/workflows/main.yml
name: Main Workflow
on:
push:
branches: [ main ]
jobs:
call-workflow:
uses: ./.github/workflows/reusable.yml
with:
environment: production
secrets:
api-token: ${{ secrets.API_TOKEN }}
3. 工作流中的上下文和表达式
GitHub Actions 提供了丰富的上下文和表达式系统:
jobs:
example:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Conditional step
if: ${{ github.event_name == 'pull_request' && github.event.action == 'opened' }}
run: echo "This is a new pull request"
- name: Use expressions
run: echo "Repository has ${{ github.event.repository.stargazers_count }} stars"
常用的上下文包括:
github:GitHub 相关信息env:环境变量job:当前作业信息steps:当前作业的步骤信息runner:运行器信息secrets:密钥vars:变量
4. 缓存依赖
使用缓存可以加速工作流执行:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Cache Node modules
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
run: npm ci
这将缓存 npm 依赖,显著减少后续工作流运行的安装时间。1 2
5. 构建矩阵与并行执行
构建矩阵允许在多种配置下并行测试:
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
max-parallel: 4
matrix:
os: [ubuntu-latest, windows-latest]
python-version: [3.8, 3.9, 3.10]
exclude:
- os: windows-latest
python-version: 3.10
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Run tests
run: pytest
fail-fast: false 确保一个配置失败不会立即停止其他配置的执行,max-parallel 限制并行执行的作业数量。1 3
完整示例
以下是一个综合性的 GitHub Actions 工作流示例,包含构建、测试和部署阶段:
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
workflow_dispatch:
inputs:
deploy_environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
env:
NODE_VERSION: '16'
jobs:
lint:
name: 代码检查
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: 设置 Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: 安装依赖
run: npm ci
- name: 运行 ESLint
run: npm run lint
test:
name: 单元测试
needs: lint
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
node-version: [14, 16, 18]
exclude:
- os: windows-latest
node-version: 14
steps:
- uses: actions/checkout@v3
- name: 使用 Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: 安装依赖
run: npm ci
- name: 运行测试
run: npm test
- name: 上传测试覆盖率
if: matrix.os == 'ubuntu-latest' && matrix.node-version == 16
uses: actions/upload-artifact@v3
with:
name: coverage-report
path: coverage/
build:
name: 构建应用
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: 设置 Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: 安装依赖
run: npm ci
- name: 构建
run: npm run build
- name: 上传构建产物
uses: actions/upload-artifact@v3
with:
name: build-files
path: dist/
retention-days: 7
deploy-staging:
name: 部署到测试环境
if: github.event_name == 'push' && github.ref == 'refs/heads/develop' || (github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_environment == 'staging')
needs: build
runs-on: ubuntu-latest
environment:
name: staging
url: https://staging.example.com
steps:
- uses: actions/checkout@v3
- name: 下载构建产物
uses: actions/download-artifact@v3
with:
name: build-files
path: dist
- name: 部署到测试服务器
run: |
echo "Deploying to staging..."
./deploy.sh staging
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
SERVER_URL: ${{ vars.STAGING_SERVER }}
deploy-production:
name: 部署到生产环境
if: github.event_name == 'push' && github.ref == 'refs/heads/main' || (github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_environment == 'production')
needs: build
runs-on: ubuntu-latest
environment:
name: production
url: https://example.com
steps:
- uses: actions/checkout@v3
- name: 下载构建产物
uses: actions/download-artifact@v3
with:
name: build-files
path: dist
- name: 部署到生产服务器
run: |
echo "Deploying to production..."
./deploy.sh production
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
SERVER_URL: ${{ vars.PRODUCTION_SERVER }}
这个工作流包含代码检查、多环境测试、构建和根据不同条件部署到测试或生产环境。1 2 3 4
最佳实践
-
保持工作流文件简洁:将复杂逻辑移至脚本文件,保持工作流配置清晰可读。3
-
使用可复用工作流:对于常见任务,创建可复用的工作流以避免重复代码。1
-
合理使用缓存:缓存依赖项可以显著提高构建速度,特别是对于大型项目。2
-
设置超时限制:为作业设置合理的超时时间,避免异常情况下长时间占用资源。1
-
使用环境保护规则:为生产环境配置审批流程,确保部署安全。4
-
密钥管理:敏感信息应使用 GitHub 的密钥功能存储,而非直接写入工作流文件。3
-
使用官方 Actions:优先使用 GitHub 官方维护的 Actions,它们通常更安全、更可靠。2
-
限制权限:使用
permissions字段限制工作流的权限,遵循最小权限原则。1
通过遵循这些最佳实践,可以创建高效、安全、可维护的 GitHub Actions 工作流。4